home *** CD-ROM | disk | FTP | other *** search
/ Amiga News 96 / Amiga News 96.iso / amig_ad_os / laurent_faillie / lfcinter / token.cxx < prev    next >
C/C++ Source or Header  |  1977-12-31  |  16KB  |  442 lines

  1. /***************************************************************************\
  2. *  Token.cxx                                                                *
  3. *  Projet : LFCInter                                                        *
  4. *      © LFSoft 1995-96                                                     *
  5. *                                                                           *
  6. *   Méthodes de la classe '_token'                                          *
  7. *                                                                           *
  8. \************* Voir LFCInter.cxx pour plus d'informations ******************/
  9.  
  10. #include "Token.h"
  11.  
  12. #define isid(c) (isalnum((unsigned char)(c)) || ((c)=='_'))
  13.  
  14. static struct _motsclef {
  15.     const char *nom;
  16.     int type;   // valeur du symbole
  17.     bool mda;   // Le message indiquant un warning a déjà été affiché (valide uniquement pour les mots clefs ignorés)
  18.     int h;
  19.  
  20.     bool cmp(const char *, int, int);
  21. } motsclef[] = {
  22.     {">>="  ,smbl_sra,false,0}, // 0
  23.     {"<<="  ,smbl_sla,false,0}, // 1
  24.     {"+="  ,smbl_aa,false,0},   // 2
  25.     {"-="  ,smbl_sa,false,0},   // 3
  26.     {"*="  ,smbl_ma,false,0},   // 4
  27.     {"/="  ,smbl_da,false,0},   // 5
  28.     {"%="  ,smbl_mda,false,0},  // 6
  29.     {"&="  ,smbl_anda,false,0}, // 7
  30.     {"^="  ,smbl_xora,false,0}, // 8
  31.     {"|="  ,smbl_ora,false,0},  // 9
  32.     {">>"  ,smbl_sr,false,0},   // 10
  33.     {"<<"  ,smbl_sl,false,0},   // 11
  34.     {"++"  ,smbl_inc,false,0},  // 12
  35.     {"--"  ,smbl_dec,false,0},  // 13
  36.     {"&&"  ,smbl_land,false,0}, // 14
  37.     {"||"  ,smbl_lor,false,0},  // 15
  38.     {"<="  ,smbl_lle,false,0},  // 16
  39.     {">="  ,smbl_lge,false,0},  // 17
  40.     {"=="  ,smbl_lequ,false,0}, // 18
  41.     {"!="  ,smbl_lne,false,0},  // 19
  42.     {"/*"  ,smbl_debc,false,0}, // 20
  43.     {"*/"  ,smbl_finc,false,0}, // 21
  44.     {"//"  ,smbl_debcppc,false,0}, // 22
  45. #define PREMIERMOTCLEF  23
  46.     {"float"   ,-1 ,false,0},   // Ce doit être le premier des token alphabétic
  47.     {"struct"  ,-1 ,false,0},
  48.     {"union"   ,-1 ,false,0},
  49.     {"typedef" ,-1 ,false,0},
  50.     {"double"  ,-1 ,false,0},
  51.     {"static"  ,-1 ,false,0},
  52.     {"goto"  , /*smbl_goto*/ -1,false,0}, // J'aime les gotos mais ils compliquent les libérations de variables dynamiques
  53.     {"register",-2 ,false,0},
  54.     {"volatile",-2 ,false,0},
  55.     {"short"   ,-2 ,false,0},
  56.     {"const"   ,-2 ,false,0},
  57.     {"long"    ,-2 ,false,0},
  58.     {"extern"  ,-2 ,false,0},
  59.     {"signed"  ,-2 ,false,0},
  60.     {"unsigned",-2 ,false,0},
  61.     {"auto"    ,-2 ,false,0},
  62.     {"void"  ,smbl_void,false,0},
  63.     {"int"   ,smbl_int,false,0},
  64.     {"char"  ,smbl_char,false,0},
  65.     {"for"   ,smbl_for,false,0},
  66.     {"do"    ,smbl_do,false,0},
  67.     {"while" ,smbl_while,false,0},
  68.     {"switch",smbl_switch,false,0},
  69.     {"case"  ,smbl_case,false,0},
  70.     {"default"  ,smbl_default,false,0},
  71.     {"if"    ,smbl_if,false,0},
  72.     {"else"  ,smbl_else,false,0},
  73.     {"break" ,smbl_break,false,0},
  74.     {"continue",smbl_continue,false,0},
  75.     {"return",smbl_return,false,0},
  76.     {"exit"  ,smbl_exit,false,0},
  77.     {"enum"  ,smbl_enum,false,0},
  78.     {"printf",smbl_printf,false,0},
  79.     {"sprintf",smbl_sprintf,false,0},
  80.     {"scanf" ,smbl_scanf,false,0},
  81.     {"putchar"  ,smbl_putchar,false,0},
  82.     {"puts"  ,smbl_puts,false,0},
  83. /*    {"sizeof",smbl_sizeof,false,0}, */
  84.     {"gets",smbl_gets,false,0},
  85.     {"getchar",smbl_getchar,false,0},
  86.     {"flushstdout",smbl_flushstdout,false,0}, // Fonction non standard
  87.     {"atoi",smbl_atoi,false,0},
  88.     {"strcat",smbl_strcat,false,0},
  89.     {"strchr",smbl_strchr,false,0},
  90.     {"strcmp",smbl_strcmp,false,0},
  91.     {"strcpy",smbl_strcpy,false,0},
  92.     {"strerror",smbl_strerror,false,0},
  93.     {"strlen",smbl_strlen,false,0},
  94.     {"strncat",smbl_strncat,false,0},
  95.     {"strncmp",smbl_strncmp,false,0},
  96.     {"strncpy",smbl_strncpy,false,0},
  97.     {"strrchr",smbl_strrchr,false,0},
  98.     {"strdup",smbl_strdup,false,0},
  99.     {"stricmp",smbl_stricmp,false,0},
  100.     {"strcasecmp",smbl_strcasecmp,false,0},
  101.     {"strnicmp",smbl_strnicmp,false,0},
  102.     {"strncasecmp",smbl_strncasecmp,false,0},
  103.     {"strpbrk",smbl_strpbrk,false,0},
  104.     {"strstr",smbl_strstr,false,0},
  105.     {"strcoll",smbl_strcoll,false,0},
  106.     {"strcspn",smbl_strcspn,false,0},
  107.     {"strspn",smbl_strspn,false,0},
  108.     {"strtok",smbl_strtok,false,0},
  109.     {"strtol",smbl_strtol,false,0},
  110.     {"swab",smbl_swab,false,0},
  111.     {"memchr",smbl_memchr,false,0},
  112.     {"memcmp",smbl_memcmp,false,0},
  113.     {"memcpy",smbl_memcpy,false,0},
  114.     {"memmove",smbl_memmove,false,0},
  115.     {"memset",smbl_memset,false,0},
  116.     {"memccpy",smbl_memccpy,false,0},
  117.     {"system",smbl_system,false,0},
  118.     {"isdigit",smbl_isdigit,false,0},
  119.     {"islower",smbl_islower,false,0},
  120.     {"isspace",smbl_isspace,false,0},
  121.     {"ispunct",smbl_ispunct,false,0},
  122.     {"isupper",smbl_isupper,false,0},
  123.     {"isalpha",smbl_isalpha,false,0},
  124.     {"isxdigit",smbl_isxdigit,false,0},
  125.     {"isalnum",smbl_isalnum,false,0},
  126.     {"isprint",smbl_isprint,false,0},
  127.     {"isgraph",smbl_isgraph,false,0},
  128.     {"iscntrl",smbl_iscntrl,false,0},
  129.     {"isascii",smbl_isascii,false,0},
  130.     {"isiso",smbl_isiso,false,0},
  131.     {"toupper",smbl_toupper,false,0},
  132.     {"tolower",smbl_tolower,false,0},
  133.     {"toiso",smbl_toiso,false,0},
  134.     {"time",smbl_time,false,0},
  135.     {"ctime",smbl_ctime,false,0},
  136.     {"clock",smbl_clock,false,0},
  137.     {"sleep",smbl_sleep,false,0},
  138.     {"realloc",smbl_realloc,false,0},
  139.     {"malloc",smbl_malloc,false,0},
  140.     {"free"  ,smbl_free,false,0},
  141.     {NULL,0,false,0}
  142. };
  143.  
  144. bool _motsclef::cmp(const char *avec, int lenavec, int havec){
  145.          if(!h) h= calchash(nom); // Le code hash n'était pas encore calculé
  146.  
  147.          if(h!=havec)    // Les codes hashs ne correpondent pas
  148.                   return false;
  149.  
  150.                   // Pour gagner du temps, on compare les chaînes tout en calculant leur longueur
  151.          register int l;
  152.          for(l=0; l<lenavec ; l++)
  153.                   if(nom[l] != avec[l]) return false; // Une lettre ne correspond pas
  154.  
  155.                   // On a comparé toutes les lettres sur la longueur d'avec: nom doit être fini
  156.          return !nom[l];
  157. }
  158.  
  159. void _token::construit( bool ign ){
  160. /* Construit les éléments de l'objet en fonction de ptr.
  161.  *      . Décode le token qui est actuellement pointé.
  162.  *      . Affiche les éventuels warnings associés aux mots clefs ignorés
  163.  *      . Affiche les erreurs associés aux mots clefs non supportés
  164.  *  -> ign indique si les messages doivent être ignorés (dans des commentaires)
  165.  */
  166.  
  167.     if(!ptr){ // Le pointeur n'est pas valide
  168.         val = len = hash = 0;
  169.         return;
  170.     }
  171.  
  172.     for(; *ptr; ptr++) // On ignore tous les caractères de contrôle
  173.         if((unsigned char)(*ptr)>' ') break;
  174. /*        if((unsigned char)(*ptr)>' ' && *ptr != '\\') break; */
  175.  
  176.     if(!isalpha((unsigned char)(*ptr)) && *ptr !='_' ){ // On lit autre chose qu'une lettre
  177.         register int i;
  178.         hash = 0;
  179.         for(i=0;motsclef[i].type>=0;i++){ // Ne lit que les symboles spéciaux
  180.             len = strlen(motsclef[i].nom);
  181.             if(!strncmp(motsclef[i].nom,ptr,len)){ // On a trouvé !
  182.                 val = motsclef[i].type;
  183.                 return;
  184.             }
  185.         }
  186.         len = 1; val = *ptr;
  187.         return;
  188.     } else { // Ou un ID ou un mot clef
  189.         for(len=1; isid( *(ptr+len) ); len++); // Calcul de la longueur du token
  190.  
  191.         hash = calchash(obj().c_str());
  192.         register int i;
  193.  
  194.         for( i=PREMIERMOTCLEF; motsclef[i].nom; i++ ){
  195.             if( motsclef[i].cmp( ptr, len, hash )){ // On a trouvé un mot clef
  196.                 if((val = motsclef[i].type)<0 && !ign){
  197.                     if(val == -2 && !motsclef[i].mda){
  198.                         cerr << "*R* Ligne " << calcligne(ptr) << ":  Le mot clef '" << motsclef[i].nom << "' est ignoré.\n";
  199.                         motsclef[i].mda=true;
  200.                     } else { // -1 donc erreur
  201.                         cerr << "*R* Ligne " << calcligne(ptr) << ":  Le mot clef '" << motsclef[i].nom << "' n'est pas supporté par ce programme.\n";
  202.                         exit(5);
  203.                     }
  204.                 }
  205.                 return;
  206.             }
  207.         }
  208.         val = smbl_id;
  209.     }
  210. }
  211.  
  212. string _token::obj(){
  213.     if(!ptr) return "";
  214.  
  215.     return string(ptr,
  216. #ifdef STRCONSTOFF
  217.         0,
  218. #endif
  219.         len);
  220. }
  221.  
  222. _token _token::operator ++ (){ // Préfixe
  223. /* Vas au token suivant :  Les commentaires sont ignorés...
  224.  * Pour accélérer les choses, les commentaires ne sont pas décodés, mais
  225.  * uniquement lus.
  226.  */
  227.     if(!ptr || !len) return *this; // Une des infos de base est invalide
  228.     ptr += len;
  229.  
  230. autre:
  231.     construit();
  232.  
  233.     if(val == smbl_debcppc){ // Lecture d'un commentaire C++
  234.         len = 0;
  235.         for(; *ptr != '\n' && *ptr; ptr++);
  236.         ptr++;
  237.         goto autre;
  238.     } else if(val == smbl_debc){ // Lecture d'un commentaire C
  239.         int niveau; // Nombre de commentaires imbriqués
  240.         ptr += len; // Saute le début de commentaire
  241.         for( niveau=1; niveau; ptr++ ){
  242.             switch(*ptr){
  243.             case '/':
  244.                 if(ptr[1]=='*'){ // C'est un commentaire imbriqué
  245.                     niveau++;
  246.                     ptr+=2;
  247.                 }
  248.                 break;
  249.             case '*':
  250.                 if(ptr[1]=='/'){ // Fin d'un commentaire
  251.                     niveau--;
  252.                     ptr+=2;
  253.                 }
  254.                 break;
  255.             case 0:
  256.                 cerr << "*E* Ligne " << calcligne(ptr) << ": " << niveau
  257.                      << " commentaire" << string((niveau>1)?"s":" ")
  258.                      << " n'" << string((niveau>1)?"ont":"a")
  259.                      << " pas été fermé" << string((niveau>1)?"s":" ") << ".\n";
  260.                 exit(5);
  261.             }
  262.         }
  263.         goto autre;
  264.     }
  265.  
  266.     return *this;
  267. }
  268.  
  269. _token _token::operator ++ (int){ // suffixe
  270. /* Vas au token suivant :  Les commentaires sont ignorés...
  271.  * Pour accélérer les choses, les commentaires ne sont pas décodés, mais
  272.  * uniquement lus.
  273.  */
  274.     _token bidon = *this;
  275.     ++*this;
  276.     return bidon;
  277. }
  278.  
  279. void _token::saute(const char *sep){
  280. /* Recherche la fin d'un bloc débutant sans chercher à le
  281.  * comprendre mais en respectant les règles du C !
  282.  * Si le premier caractère rencontré est:
  283.  *  '{' : Saute le bloc <d'instructions> jusqu'au '}' fermant (inclus)
  284.  *  '(' : Saute le bloc <d'arguments> jusqu'au ')' fermant (inclus)
  285.  * sinon : Saute jusqu'au 'sep' suivant (inclus)
  286.  *
  287.  *  Basés sur les sources d'LFLocalize 0.4ß © LFSoft 1994-95
  288.  */
  289.  
  290.     struct {
  291.         unsigned short int  com,        // Commentaires '/* */'
  292.                             blocf,      // Blocs '{}'
  293.                             blocc;      // Blocs '()'
  294.         char                car;        // Caractère déterminant le mode
  295.         unsigned            lcom :1;    // Commentaires C++ '//'
  296.         unsigned            slt :1;     // Le dernier caractère est '/'
  297.         unsigned            star :1;    // Le dernier caractère '*'
  298.         unsigned            ignore :1;  // Le dernier caractère '\'
  299.         unsigned            instr :1;   // Lecture d'une chaîne ""
  300.         unsigned            inchar :1;  // Lecture d'une définition de caractère ''
  301.     } status;
  302.  
  303.     status.com = status.blocf = status.blocc = 0;
  304.     status.lcom = status.slt = status.star = 0;
  305.     status.ignore = status.instr = status.inchar = 0;
  306.  
  307.     if(*ptr == '{' /* } */ || *ptr == '(' /* ) */)
  308.         status.car = *ptr++;
  309.     else
  310.         status.car = 0;
  311.  
  312.     while(*ptr){
  313.         if(status.instr) switch(*ptr){ // Lecture d'une chaîne
  314.             case '\n':
  315.                 cerr << "*E* Ligne " << calcligne(ptr) << ": Chaîne non terminée !\n";
  316.                 exit(5);
  317.             case '\\':
  318.                 status.ignore ^= 1;
  319.                 break;
  320.             case '"':
  321.                 if(status.ignore)
  322.                     status.ignore = 0;
  323.                 else
  324.                     status.instr = 0;
  325.                 break;
  326.             default:
  327.                 status.ignore = 0;
  328.         } else if(status.inchar) switch(*ptr){ // Lecture d'une chaîne
  329.             case '\n':
  330.                 cerr << "*E* Ligne " << calcligne(ptr) << ": caractère '' non terminée !\n";
  331.                 exit(5);
  332.             case '\\':
  333.                 status.ignore ^= 1;
  334.                 break;
  335.             case '\'':
  336.                 if(status.ignore)
  337.                     status.ignore = 0;
  338.                 else
  339.                     status.inchar = 0;
  340.                 break;
  341.             default:
  342.                 status.ignore = 0;
  343.         } else if(status.lcom){ // Lecture d'un commentaire C++
  344.             if( *ptr == '\n' ) status.lcom = 0;
  345.         } else if(status.com){ // Lecture d'un commentaire
  346.             if( *ptr == '*' ){
  347.                 if(status.slt){ // Imbrication ?
  348.                     status.slt = 0;
  349.                     status.com++;
  350.                     status.star = 0;
  351.                 } else
  352.                     status.star = 1;
  353.             } else if( *ptr == '/' ){
  354.                 if(status.star){    // Fermeture
  355.                     status.star = 0; status.com--;
  356.                 } else
  357.                     status.slt = 1;
  358.             } else {
  359.                 status.star = 0; status.slt = 0;
  360.             }
  361.         } else {    // Autre
  362.             if(status.ignore)
  363.                 status.ignore = 0;
  364.             else switch(*ptr){
  365.             case '/':
  366.                 if(status.slt){ // Commentaire C++ ?
  367.                     status.slt = 0; status.lcom = 1;
  368.                 } else if(status.star) {
  369.                     cerr << "*E* Ligne " << calcligne(ptr) << ": Fermeture superflue d'un commentaire.\n";
  370.                     exit(5);
  371.                 } else
  372.                     status.slt = 1;
  373.                 break;
  374.             case '*':
  375.                 if(status.slt){ // Nouveau commentaire ?
  376.                     status.com++; status.slt =0;
  377.                 } else
  378.                     status.star = 1;
  379.                 break;
  380.             case '\\':
  381.                 status.ignore = 1; status.star=status.slt=0;
  382.                 break;
  383.             case '\'':
  384.                 status.inchar = 1;status.star=status.slt=0;
  385.                 break;
  386.             case '"':
  387.                 status.instr = 1;status.star=status.slt=0;
  388.                 break;
  389.             case '{': /* } */
  390.                 status.blocf++;status.star=status.slt=0;
  391.                 break;
  392.             case '(': /* ) */
  393.                 status.blocc++;status.star=status.slt=0;
  394.                 break;
  395. /* { */     case '}':
  396.                 if(!status.blocf){
  397.                     if(status.blocc){
  398.                         cerr << "*E* Ligne " << calcligne(ptr) << ": Erreur d'imbrication de blocs '{}' et '()'.\n";
  399.                         exit(5);
  400.                     }
  401.  
  402.                     if(status.car == '{' /*}*/ || strchr(sep,*ptr)){ // Le bloc est sauté
  403.                         construit(); (*this)++; return;
  404.                     } else {
  405.                         cerr << "*E* Ligne " << calcligne(ptr) << ": Fermeture superflue d'un bloc '{}'.\n";
  406.                         exit(5);
  407.                     }
  408.                 } else
  409.                     --status.blocf;
  410.                 status.star=0;status.slt=0;
  411.                 break;
  412. /* ( */         case ')':
  413.                 if(!status.blocc){
  414.                     if(status.blocf){
  415.                         cerr << "*E* Ligne " << calcligne(ptr) << ": Erreur d'imbrication de blocs '{}' et '()'.\n";
  416.                         exit(5);
  417.                     }
  418.  
  419.                     if(status.car == '(' /*)*/ || strchr(sep,*ptr)){ // Le bloc est sauté
  420.                         construit(); (*this)++; return;
  421.                      } else {
  422.                         cerr << "*E* Ligne " << calcligne(ptr) << ": Fermeture superflu d'un bloc '()'.\n";
  423.                         exit(5);
  424.                     }
  425.                 } else
  426.                     --status.blocc;
  427.                 status.star=0;status.slt=0;
  428.                 break;
  429.             default:
  430.                 if(strchr(sep,*ptr)){ // Est-ce un des séparateurs recherchés ?
  431.                     if(!status.blocc && !status.blocf && status.car != '{' /* } */ && status.car !='(' /* ) */){
  432.                         construit(); (*this)++; return;
  433.                     }
  434.                 }
  435.                 status.star=0;status.slt=0;
  436.             }
  437.         }
  438.         ptr++;
  439.     }
  440.     construit();
  441. }
  442.